#include "pch.h"
#include "lua_engine.h"
#include "mgr.h"
#include <fstream>  
#include <sstream>  
#include <string>


std::string read_file(const std::string& filepath) {
	std::ifstream file(filepath);
	std::stringstream buffer;
	buffer << file.rdbuf();
	return buffer.str();
}


uintptr base() {
	return Mgr::get()->module_base();
}

void bypass_lua_invoke_checking() {
	*((uint64*)(base() + RVA_MODULE_START_CHECKING_BASE)) = 0x1000;
	*((uint64*)(base() + RVA_MODULE_TEXT_END_CHECKING_BASE)) = 0x7FFFFFFFFFFFFFFF;
}


uintptr lptr() {
	__try {
		return r8(base() + RVA_LUAPTR_BASE);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0;
}


int pcall(int nargs, int nresults, int errfunc) {
	__try {
		LuaPcall fnpcall = (LuaPcall)(base() + RVA_LUA_PCALL_CALL);
		int ret = fnpcall(lptr(), 0, LUA_MULTRET, 0);
		// dbgprint("codergege pcall ok ret=%d", ret);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0;
}

int lua_loadstring(const char* s) {
	int success = 0;
	LuaBLoadstring fn_luab_loadstring = (LuaBLoadstring)0x00007FF793E999B0;
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	lua_pushstring(s);
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	int status = fn_luab_loadstring(lptr());
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	if (status == 2) {
        dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
		const char* err = lua_tostring(-1);
		dbgprint("codergege ERROR msg=%s", err);
		return 1;
	}
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	return success;
	/*
	LuaLLoadbuffer lua_loadbuffer = (LuaLLoadbuffer)(base() + RVA_LUA_LOADBUFFER_CALL);
	__try {
		return lua_loadbuffer(lptr(), s, (int)strlen(s), s);
	} __except(1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0;
	*/
}

int lua_dostring(const char* luastring) {
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	int top = lua_gettop();
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	int status = lua_loadstring(luastring);
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	if (status == 0) {
		__try {
			dbgprint("codergege %llX [%s][%d]", lptr(), __FUNCTION__, __LINE__);
			status = pcall(0, LUA_MULTRET, 0);
		} __except (1) {
			dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
			status = 1;
		}
	}
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	lua_settop(top);
    dbgprint("codergege %s %d", __FUNCTION__, __LINE__);
	return status;
}

int lua_dofile(const char* filepath) {
	auto content = read_file(filepath);
	return lua_dostring(content.c_str());
}

void lua_settop(int index) {
	LuaSettop fn_lua_settop = (LuaSettop)(base() + RVA_LUA_SETTOP_CALL);
	__try {
		fn_lua_settop(lptr(), index);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}
int lua_gettop() {
	LuaGettop fn_lua_gettop = (LuaGettop)(base() + RVA_LUA_GETTOP_CALL);
	__try {
		return fn_lua_gettop(lptr());
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0;
}

void lua_register(const char* libname, uintptr table) {
	LuaLRegister fn_lua_register = (LuaLRegister)(base() + RVA_LUAL_REGISTER_CALL);
	__try {
		fn_lua_register(lptr(), libname, table);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}

double lua_tonumber(int index) {
	LuaTonumber fn_lua_tonumber = (LuaTonumber)(base() + RVA_LUA_TONUMBER_CALL);
	__try {
		return fn_lua_tonumber(lptr(), index);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0.0;
}
int lua_tointeger(int index) {
	LuaTointeger fn_lua_tointeger = (LuaTointeger)(base() + RVA_LUA_TOINTEGER_CALL);
	__try {
		return fn_lua_tointeger(lptr(), index);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return 0;
}
boolean lua_toboolean(int index) {
	LuaToboolean fn_lua_toboolean = (LuaToboolean)(base() + RVA_LUA_TOBOOLEAN_CALL);
	__try {
		return static_cast<boolean>(fn_lua_toboolean(lptr(), index));
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return false;
}
const char* lua_tostring(int index) {
	LuaTolstring fn_lua_tolstring = (LuaTolstring)(base() + RVA_LUA_TOLSTRING_CALL);
	__try {
		return fn_lua_tolstring(lptr(), index, nullptr);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
	return "";
}
void lua_pushnumber(double n) {
	LuaPushnumber fn_lua_pushnumber = (LuaPushnumber)(base() + RVA_LUA_PUSHNUMBER_CALL);
	__try {
		fn_lua_pushnumber(lptr(), n);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}
void lua_pushinteger(int n) {
	LuaPushinteger fn_lua_pushinteger = (LuaPushinteger)(base() + RVA_LUA_PUSHINTEGER_CALL);
	__try {
		fn_lua_pushinteger(lptr(), n);
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}

void lua_pushboolean(boolean b) {
	LuaPushboolean fn_lua_pushboolean = (LuaPushboolean)(base() + RVA_LUA_PUSHBOOLEAN_CALL);
	__try {
		fn_lua_pushboolean(lptr(), static_cast<int>(b));
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}

void lua_pushstring(const char* s) {
	LuaPushlstring fn_lua_pushlstring = (LuaPushlstring)(base() + RVA_LUA_PUSHLSTRING_CALL);
	__try {
		fn_lua_pushlstring(lptr(), s, strlen(s));
	} __except (1) {
		dbgprint("codergege ERROR %s %d", __FUNCTION__, __LINE__);
	}
}

